import Datastore from 'nedb'
import path from 'path'
import { remote } from 'electron'
const fs = require('fs')

const initdbDefault = require('./initdb/initdb.json')

// promisify fs utils, utf-8
const readFileP = function (filepath, dataHandler) {
  return new Promise((resolve, reject) => {
    return fs.readFile(filepath, 'utf-8', (err, data) => {
      if (err) {
        return reject(err)
      } else {
        const jsonData = dataHandler(data)
        return resolve(jsonData)
      }
    })
  })
}

// promisify db utils
const promiseFactory = function (db, fn) {
  const newFn = function () {
    return new Promise((resolve, reject) => {
      var args = Array.slice(arguments)
      const callback = (err, s = 'ok') => {
        if (err) {
          return reject(err)
        } else {
          return resolve(s)
        }
      }
      args.push(callback)
      db[fn].apply(db, args)
    })
  }
  return newFn
}

const removeP = (db) => promiseFactory(db, 'remove')
const insertP = (db) => promiseFactory(db, 'insert')

const reloadP = (db) => promiseFactory(db, 'loadDatabase')
const countP = (db) => promiseFactory(db, 'count')
const findP = (db) => promiseFactory(db, 'find')

const cardsDB = new Datastore({
  autoload: true,
  filename: path.join(remote.app.getPath('userData'), '/cards.db')
})

const settingsDB = new Datastore({
  autoload: true,
  filename: path.join(remote.app.getPath('userData'), '/settings.db')
})

const removeAll = () => {
  return Promise.all([
    removeP(settingsDB)({}, {multi: true}),
    removeP(cardsDB)({}, {multi: true})])
    .catch(err => console.log(err))
}

const insertAll = (initdb) => {
  return Promise.all([
    insertP(settingsDB)(initdb.settings),
    insertP(cardsDB)(initdb.cards)])
    .catch(err => console.log(err))
}

const resetAll = (initdb) => {
  return removeAll().then(() => insertAll(initdb))
}

const reloadAll = () => {
  return Promise.all([
    reloadP(settingsDB)(),
    reloadP(cardsDB)()])
    .catch(err => console.log(err))
}

const tryCount = (p) =>
  p()
    .then(() =>
      countP(cardsDB)({}))
    .then((count) => {
      if (count > 0) {
        return Promise.resolve(count)
      } else {
        throw Error('No records.')
      }
    })

const tryReload = (setStatus) => {
  setStatus('load')
  return tryCount(reloadAll)
    .then((count) => {
      setStatus('ready')
      return count
    })
    .catch((err) => {
      setStatus('wait')
      return console.log(err)
    })
}

const tryResetDB = (setStatus, initdb) => {
  const reset = () => {
    return resetAll(initdb)
  }
  setStatus('init')
  return tryCount(reset)
    .then((count) => {
      setStatus('ready')
      return count
    })
    .catch((err) => {
      setStatus('wait')
      return console.log(err)
    })
}

const loadInitDB = (initdbPath) => {
  if (initdbPath === '') {
    return Promise.resolve(initdbDefault)
  } else {
    return readFileP(initdbPath, JSON.parse)
      .then((data) => Promise.resolve(data))
  }
}

const tryReset = (setStatus, initdbPath) =>
  loadInitDB(initdbPath)
    .then((initdb) => tryResetDB(setStatus, initdb))

const db = {
  cards: cardsDB,
  settings: settingsDB,
  initdbDefault: initdbDefault,
  resetAll: resetAll,
  reloadAll: reloadAll,
  // reload: reloadPromise,
  count: countP,
  find: findP,
  tryReload: tryReload,
  tryReset: tryReset
}

export default db
